/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import { expect } from '@jest/globals';
import * as fse from 'fs-extra';
import JSZip from 'jszip';
import { resolve } from 'path';

import { AotCompileModeEnum } from '../../src/enum/aot-compile-mode-enum';

import { appRoot, initByStageEmptyApp, initExecuteCommand, runHvigor, runShouldFail } from './common/common';
import { ModuleBuildProfileModifier } from './common/modifier/module-build-profile-modifier';
import { ProjectBuildProfileModifier } from './common/modifier/project-build-profile-modifier';
import { Probes } from './common/probes';

async function copyExtraFiles(projectRoot: string) {
  await Promise.all([
    fse.copy(resolve(appRoot(), 'test/resources/extra/aot/index.ets'),
      resolve(projectRoot, 'entry/src/main/ets/pages/index.ets')),
    fse.copy(resolve(appRoot(), 'test/resources/extra/aot/test1.ap'), resolve(projectRoot, 'entry/test1.ap'))
  ]);
  new ProjectBuildProfileModifier(projectRoot).setRuntimeInfo('HarmonyOS', '4.0.0(10)', '4.0.0(10)')
    .outputSync();
}

describe('api10 aot tests', function () {
  test.concurrent('partial + apPath=undefined', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: true,
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      runShouldFail(projectRoot, commands,
        'The file corresponding to apPath under AoT\'s partial mode was not found in');
    });
  });

  test.concurrent('partial + apPath=notExist', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: true,
          apPath: 'notExist.ap'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      runShouldFail(projectRoot, commands,
        'The file corresponding to apPath under AoT\'s partial mode was not found in');
    });
  });

  test.concurrent('partial + apPath=notSuffix.ap', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: true,
          apPath: 'notSuffix.ap1'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      runShouldFail(projectRoot, commands, 'apPath must be with suffix ".ap".');
    });
  });

  test.concurrent('partial + apPath=valid.ap', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: true,
          apPath: 'test1.ap'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      const result = runHvigor(projectRoot, commands);

      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'entry'));

      expect(fse.readdirSync(probe.getIntermediatesLoaderOutPath())).toContain(AotCompileModeEnum.AN);

      const hapObj = await new JSZip().loadAsync(fse.readFile(
        resolve(probe.getModuleBuildOutputPath(), 'entry-default-unsigned.hap')
      ), { createFolders: true });

      expect(hapObj.files).toHaveProperty('ap/');
      expect(hapObj.files).toHaveProperty('an/');
    });
  });

  test.concurrent('type + apPath=undefined', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: false,
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      const result = runHvigor(projectRoot, commands);

      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'entry'));

      expect(fse.readdirSync(probe.getIntermediatesLoaderOutPath())).not.toContain(AotCompileModeEnum.AN);

      const hapObj = await new JSZip().loadAsync(fse.readFile(
        resolve(probe.getModuleBuildOutputPath(), 'entry-default-unsigned.hap')
      ), { createFolders: true });

      expect(hapObj.files).not.toHaveProperty('ap/');
      expect(hapObj.files).not.toHaveProperty('an/');
    });
  });

  test.concurrent('type + apPath=notExist', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: false,
          apPath: 'notExist.ap'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      const result = runHvigor(projectRoot, commands);

      expect(result.stderr.includes('The file corresponding to apPath was not found in'));

      const probe = new Probes(projectRoot, resolve(projectRoot, 'entry'));

      expect(fse.readdirSync(probe.getIntermediatesLoaderOutPath())).not.toContain(AotCompileModeEnum.AN);

      const hapObj = await new JSZip().loadAsync(fse.readFile(
        resolve(probe.getModuleBuildOutputPath(), 'entry-default-unsigned.hap')
      ), { createFolders: true });

      expect(hapObj.files).not.toHaveProperty('ap/');
      expect(hapObj.files).not.toHaveProperty('an/');
    });
  });

  test.concurrent('type + apPath=notSuffix.ap', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: false,
          apPath: 'notSuffix.ap1'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      runShouldFail(projectRoot, commands, 'apPath must be with suffix ".ap".');
    });
  });

  test.concurrent('type + apPath=valid.ap', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      await copyExtraFiles(projectRoot);
      new ModuleBuildProfileModifier(projectRoot, 'entry').setBuildOption({
        arkOptions: {
          hostPGO: false,
          apPath: 'test1.ap'
        }
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'assembleHap',
      });

      const result = runHvigor(projectRoot, commands);

      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'entry'));

      expect(fse.readdirSync(probe.getIntermediatesLoaderOutPath())).not.toContain(AotCompileModeEnum.AN);

      const hapObj = await new JSZip().loadAsync(fse.readFile(
        resolve(probe.getModuleBuildOutputPath(), 'entry-default-unsigned.hap')
      ), { createFolders: true });

      expect(hapObj.files).toHaveProperty('ap/');
      expect(hapObj.files).not.toHaveProperty('an/');
    });
  });
});
